package com.ruoyi.project.system.controller;

import java.io.IOException;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.annotation.PostConstruct;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.lang.UUID;
import cn.hutool.core.util.IdUtil;
import cn.hutool.poi.excel.ExcelUtil;
import com.alibaba.fastjson2.JSON;
import com.ruoyi.framework.aspectj.lang.annotation.Log;
import com.ruoyi.framework.aspectj.lang.enums.BusinessType;
import com.ruoyi.framework.security.LoginUser;
import com.ruoyi.framework.security.service.SysPermissionService;
import com.ruoyi.framework.security.service.TokenService;
import com.ruoyi.framework.web.controller.BaseController;
import com.ruoyi.framework.web.domain.AjaxResult;
import com.ruoyi.framework.web.page.TableDataInfo;
import com.ruoyi.project.system.domain.SysAuth;
import com.ruoyi.project.system.domain.SysAuthUser;
import com.ruoyi.project.system.domain.SysUser;
import com.ruoyi.project.system.mapper.SysAuthMapper;
import com.ruoyi.project.system.mapper.SysUserMapper;
import com.ruoyi.project.system.service.ISysAuthService;
import com.ruoyi.project.system.service.ISysUserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.*;
import com.alibaba.fastjson2.JSONObject;
import com.ruoyi.common.constant.Constants;
import com.ruoyi.common.enums.UserStatus;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.common.utils.AuthUtils;
import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.common.utils.StringUtils;
import me.zhyd.oauth.cache.AuthDefaultStateCache;
import me.zhyd.oauth.cache.AuthStateCache;
import me.zhyd.oauth.model.AuthCallback;
import me.zhyd.oauth.model.AuthResponse;
import me.zhyd.oauth.model.AuthUser;
import me.zhyd.oauth.request.AuthRequest;
import me.zhyd.oauth.utils.AuthStateUtils;

/**
 * 第三方认证授权处理
 *
 * @author ruoyi
 */
@RestController
@RequestMapping("/system/auth")
public class SysAuthController extends BaseController {
    private AuthStateCache authStateCache;

    @Autowired
    private ISysUserService userService;

    @Autowired
    private SysPermissionService permissionService;

    @Autowired
    private TokenService tokenService;

    @Autowired
    private SysUserMapper userMapper;

    @Autowired
    private SysAuthMapper authMapper;

    @Value("${alan.defaultPassword}")
    private String defaultPassword;
    Map<String, String> auths = new HashMap<>();

    @PostConstruct
    public void init() {
        for (SysAuth auth : authMapper.selectSysAuthList(new SysAuth().setStatus(Constants.ENABLE))) {
            Map<String, Object> map = new HashMap<>();
            map.put("clientId", auth.getAppId());
            map.put("clientSecret", auth.getAppKey());
            map.put("redirectUri", auth.getRedirectUri());
            auths.put(auth.getAppType(), JSON.toJSONString(map));
        }
        authStateCache = AuthDefaultStateCache.INSTANCE;
    }

    /**
     * 认证授权
     *
     * @param source
     * @throws IOException
     */
    @GetMapping("/binding/{source}")
    @ResponseBody
    @Log(title = "第三方登录", businessType = BusinessType.OTHER)
    public AjaxResult authBinding(@PathVariable("source") String source, HttpServletRequest request) throws IOException {
        LoginUser tokenUser = tokenService.getLoginUser(request);
        if (StringUtils.isNotNull(tokenUser) && userMapper.checkAuthUser(tokenUser.getUserId(), source) > 0) {
            return error(source + "平台账号已经绑定");
        }

        String obj = auths.get(source);
        if (StringUtils.isEmpty(obj)) {
            return error(source + "平台账号暂不支持");
        }
        JSONObject json = JSONObject.parseObject(obj);
        AuthRequest authRequest = AuthUtils.getAuthRequest(source, json.getString("clientId"), json.getString("clientSecret"), json.getString("redirectUri"), authStateCache);
        String authorizeUrl = authRequest.authorize(AuthStateUtils.createState());
        return success(authorizeUrl);
    }

    @SuppressWarnings("unchecked")
    @GetMapping("/social-login/{source}")
    public AjaxResult socialLogin(@PathVariable("source") String source, AuthCallback callback, HttpServletRequest request) {
        String obj = auths.get(source);
        if (StringUtils.isEmpty(obj)) {
            return AjaxResult.error(10002, "第三方平台系统不支持或未提供来源");
        }
        JSONObject json = JSONObject.parseObject(obj);
        AuthRequest authRequest = AuthUtils.getAuthRequest(source, json.getString("clientId"), json.getString("clientSecret"), json.getString("redirectUri"), authStateCache);
        AuthResponse<AuthUser> response = authRequest.login(callback);
        if (response.ok()) {
            LoginUser tokenUser = tokenService.getLoginUser(request);
            if (StringUtils.isNotNull(tokenUser)) {
                SysUser user = userMapper.selectAuthUserByUuid(source + response.getData().getUuid());
                if (StringUtils.isNotNull(user)) {
                    if (!user.getUserId().equals(SecurityUtils.getUserId())) {
                        return error(source + "账号已经被其他用户绑定");
                    }
                    String token = tokenService.createToken(SecurityUtils.getLoginUser());
                    return success().put(Constants.TOKEN, token);
                }
                // 若已经登录则直接绑定系统账号
                SysAuthUser authUser = new SysAuthUser();
                authUser.setAvatar(response.getData().getAvatar());
                authUser.setUuid(source + response.getData().getUuid());
                authUser.setUserId(SecurityUtils.getUserId());
                authUser.setUserName(response.getData().getUsername());
                authUser.setNickName(response.getData().getNickname());
                authUser.setEmail(response.getData().getEmail());
                authUser.setSource(source);
                userMapper.insertAuthUser(authUser);
                String token = tokenService.createToken(SecurityUtils.getLoginUser());
                return success().put(Constants.TOKEN, token);
            }
            SysUser authUser = userMapper.selectAuthUserByUuid(source + response.getData().getUuid());
            if (StringUtils.isNotNull(authUser)) {
                SysUser user = userService.selectUserByUserName(authUser.getUserName());
                if (StringUtils.isNull(user)) {
                    throw new ServiceException("登录用户：" + user.getUserName() + " 不存在");
                } else if (UserStatus.DELETED.getCode().equals(user.getDelFlag())) {
                    throw new ServiceException("对不起，您的账号：" + user.getUserName() + " 已被删除");
                } else if (UserStatus.DISABLE.getCode().equals(user.getStatus())) {
                    throw new ServiceException("对不起，您的账号：" + user.getUserName() + " 已停用");
                }
                LoginUser loginUser = new LoginUser(user.getUserId(), user.getDeptId(), user, permissionService.getMenuPermission(user));
                String token = tokenService.createToken(loginUser);
                return success().put(Constants.TOKEN, token);
            } else {
                //注册账号
                SysUser user = new SysUser();
                user.setUserName(IdUtil.nanoId(16));
                user.setNickName("临时昵称");
                user.setPassword(SecurityUtils.encryptPassword(defaultPassword));
//                user.setDeptId(Long.parseLong("100"));
                userService.insertUser(user);
                SysUser registerUser = userService.selectUserByUserName(user.getUserName());
                //绑定第三方登录信息
                SysAuthUser authInfo = new SysAuthUser();
                authInfo.setAvatar(response.getData().getAvatar());
                authInfo.setUuid(source + response.getData().getUuid());
                authInfo.setUserId(registerUser.getUserId());
                authInfo.setUserName(response.getData().getUsername());
                authInfo.setNickName(response.getData().getNickname());
                authInfo.setEmail(response.getData().getEmail());
                authInfo.setSource(source);
                userMapper.insertAuthUser(authInfo);
                LoginUser registerLoginUser = new LoginUser(registerUser.getUserId(), registerUser.getDeptId(), registerUser, permissionService.getMenuPermission(registerUser));
                String token = tokenService.createToken(registerLoginUser);
                return success().put(Constants.TOKEN, token);
            }
        }
        return AjaxResult.error(10002, "对不起，授权信息验证不通过，请联系管理员");
    }

    /**
     * 取消授权
     */
    @DeleteMapping(value = "/unlock/{authId}")
    public AjaxResult unlockAuth(@PathVariable Long authId) {
        return toAjax(userMapper.deleteAuthUser(authId));
    }


    @Autowired
    private ISysAuthService sysAuthService;

    /**
     * 查询第三方登录列表
     */
    @PreAuthorize("@ss.hasPermi('system:auth:list')")
    @GetMapping("/list")
    public TableDataInfo list(SysAuth sysAuth) {
        startPage();
        List<SysAuth> list = sysAuthService.selectSysAuthList(sysAuth);
        return getDataTable(list);
    }

    /**
     * 查询所有第三方登录列表
     */
    @PreAuthorize("@ss.hasPermi('system:auth:all')")
    @Log(title = "第三方登录", businessType = BusinessType.OTHER)
    @GetMapping("/all/sysAuths")
    public AjaxResult all(SysAuth sysAuth) {
        List<SysAuth> list = sysAuthService.selectSysAuthList(sysAuth);
        return success(list);
    }

    /**
     * 获取第三方登录详细信息
     */
    @PreAuthorize("@ss.hasPermi('system:auth:query')")
    @GetMapping(value = "/{id}")
    public AjaxResult getInfo(@PathVariable("id") Long id) {
        return success(sysAuthService.selectSysAuthById(id));
    }

    /**
     * 新增第三方登录
     */
    @PreAuthorize("@ss.hasPermi('system:auth:add')")
    @Log(title = "第三方登录", businessType = BusinessType.INSERT)
    @PostMapping
    public AjaxResult add(@RequestBody SysAuth sysAuth) {
        return toAjax(sysAuthService.insertSysAuth(sysAuth));
    }

    /**
     * 修改第三方登录
     */
    @PreAuthorize("@ss.hasPermi('system:auth:edit')")
    @Log(title = "第三方登录", businessType = BusinessType.UPDATE)
    @PutMapping
    public AjaxResult edit(@RequestBody SysAuth sysAuth) {
        return toAjax(sysAuthService.updateSysAuth(sysAuth));
    }

    /**
     * 删除第三方登录
     */
    @PreAuthorize("@ss.hasPermi('system:auth:remove')")
    @Log(title = "第三方登录", businessType = BusinessType.DELETE)
    @DeleteMapping("/{ids}")
    public AjaxResult remove(@PathVariable Long[] ids) {
        return toAjax(sysAuthService.deleteSysAuthByIds(ids));
    }
}
